package com.bolinfest.closure;

import java.util.List;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.javascript.jscomp.CompilationLevel;
import com.google.javascript.jscomp.Compiler;
import com.google.javascript.jscomp.CompilerOptions;
import com.google.javascript.jscomp.JSSourceFile;
import com.google.javascript.jscomp.PropertyRenamingPolicy;
import com.google.javascript.jscomp.VariableRenamingPolicy;

/** An example of how to call the Closure Compiler programmatically. */
public final class StripTypeOnlyExample {

  /** This is a utility class that is not meant to be instantiated. */
  private StripTypeOnlyExample() {};

  /**
   * Compiles the code using the specified configuration.
   * @param code JavaScript source code to compile.
   * @param level The compilation level to use when compiling the code.
   * @param externs to use when compiling the code.
   * @return The compiled version of the code.
   */
  public static String compile(String code, CompilationLevel level,
      List<JSSourceFile> externs) {
    Compiler compiler = new Compiler(); 
    CompilerOptions options = new CompilerOptions();    
    level.setOptionsForCompilationLevel(options);
    options.stripTypePrefixes = ImmutableSet.of("goog.debug", "goog.asserts");
    //options.stripNameSuffixes = ImmutableSet.of("logger", "logger_");

    options.prettyPrint = true;
    options.variableRenaming = VariableRenamingPolicy.OFF;
    options.propertyRenaming = PropertyRenamingPolicy.OFF;
    options.inlineFunctions = false;
    options.inlineAnonymousFunctionExpressions = false;
    options.inlineLocalFunctions = false;
    options.inlineLocalVariables = false;
    options.inlineGetters = false;
    options.devirtualizePrototypeMethods = false;

    final String path = "../closure-library/closure/goog/";
    JSSourceFile[] inputArray = new JSSourceFile[] {
        JSSourceFile.fromFile(path + "base.js"),
        JSSourceFile.fromFile(path + "object/object.js"),
        JSSourceFile.fromFile(path + "array/array.js"),
        JSSourceFile.fromFile(path + "string/string.js"),
        JSSourceFile.fromFile(path + "iter/iter.js"),
        JSSourceFile.fromFile(path + "structs/structs.js"),
        JSSourceFile.fromFile(path + "structs/map.js"),
        JSSourceFile.fromFile(path + "structs/set.js"),
        JSSourceFile.fromFile(path + "debug/debug.js"),
        JSSourceFile.fromFile(path + "debug/logrecord.js"),
        JSSourceFile.fromFile(path + "debug/logger.js"),
        JSSourceFile.fromCode("input.js", code)
        };
    JSSourceFile[] externsArray = externs.toArray(new JSSourceFile[0]);

    compiler.compile(externsArray, inputArray, options);
    return compiler.toSource();
  }

  /** Runs compile() using some dummy inputs and prints the result. */
  public static void main(String[] args) {
    // Turn off the logging so it does not clutter up the output.
    // Logger.getLogger("com.google.javascript.jscomp").setLevel(Level.OFF);
    
    // To get the complete set of externs, the logic in
    // CompilerRunner.getDefaultExterns() should be used here.
    final String path = "../closure-compiler/externs/";
    List<JSSourceFile> externs = ImmutableList.of(
        JSSourceFile.fromFile(path + "es3.js"),
        JSSourceFile.fromFile(path + "w3c_dom1.js"),
        JSSourceFile.fromFile(path + "w3c_dom2.js"),
        JSSourceFile.fromFile(path + "w3c_dom3.js"),
        JSSourceFile.fromFile(path + "w3c_event.js"),
        JSSourceFile.fromFile(path + "w3c_range.js"),
        JSSourceFile.fromFile(path + "w3c_css.js"),
        JSSourceFile.fromFile(path + "gecko_dom.js"),
        JSSourceFile.fromFile(path + "gecko_event.js"),
        JSSourceFile.fromFile(path + "ie_css.js"),
        JSSourceFile.fromFile(path + "ie_dom.js"),
        JSSourceFile.fromFile(path + "window.js")
        );

    // Run the Compiler.
    String compiledCode = compile(
          "goog.provide('example.MyClass');"
        + "/** @constructor */example.MyClass = function() { this.id = Math.random(); };"
        + "example.MyClass.prototype.logger = goog.debug.Logger.getLogger('example.MyClass');"
        + "example.MyClass.prototype.getId = function() { this.logger.fine('getId called'); return this.id; };"
        + "var hello = function(name) {"
        + "  goog.debug.expose({a:1,b:2});"
        + "  var m = new example.MyClass();"
        + "  var blogger = Math.random();"
        + "  var logger = m.logger;"
        + "  var id = m.getId();"
        + "  alert('Hello, ' + name + logger.toString() + id);"
        + "};"
        + "hello('New user');",
        CompilationLevel.ADVANCED_OPTIMIZATIONS,
        externs);

    // Print the result, which is: alert("Hello, New user");
    System.out.println(compiledCode);
  }
}